package com.gframework.util.encry;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.lang.Nullable;

/**
 * 加密解密工具类.
 * <p>
 * apache的工具库已经提供了一个{@link DigestUtils}类用于处理md5，sha等散列hash算法。
 * 而此工具类是用于处理AES，DES这类对称加密算法的。用法与{@link DigestUtils}几乎一样。
 * <p>
 * 其中对于返回的hex字符串均为小写
 * 
 * @since 1.0.0
 * @author Ghwolf
 * @see DigestUtils
 * @see Hex
 * @see RSAUtils
 * @see FillMode FillMode 填充模式枚举类
 * @see EncryptionMode EncryptionMode 加密模式枚举类
 * @see EncryptType EncryptType 加密算法类型枚举类
 */
public class EncryptUtils {

	private EncryptUtils() {
	}

	// ############## encrypt

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, byte[] data, String password) {
		return encrypt(type, type.getDefaultEncryptionMode(), data, password);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, byte[] data, String password) {
		return Hex.encodeHexString(encrypt(type, type.getDefaultEncryptionMode(), data, password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, byte[] data, String password) {
		return Base64.getEncoder().encodeToString(encrypt(type, type.getDefaultEncryptionMode(), data, password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, String data, String password) {
		return encrypt(type, type.getDefaultEncryptionMode(), data.getBytes(StandardCharsets.UTF_8), password);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, String data, String password) {
		return Hex.encodeHexString(
				encrypt(type, type.getDefaultEncryptionMode(), data.getBytes(StandardCharsets.UTF_8), password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, String data, String password) {
		return Base64.getEncoder().encodeToString(
				encrypt(type, type.getDefaultEncryptionMode(), data.getBytes(StandardCharsets.UTF_8), password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, byte[] data, String password) {
		return encrypt(type, enctyptionMode, type.getDefaultFillMode(), data, password);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, byte[] data, String password) {
		return Hex.encodeHexString(encrypt(type, enctyptionMode, type.getDefaultFillMode(), data, password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, byte[] data, String password) {
		return Base64.getEncoder()
				.encodeToString(encrypt(type, enctyptionMode, type.getDefaultFillMode(), data, password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, String data, String password) {
		return encrypt(type, enctyptionMode, type.getDefaultFillMode(), data.getBytes(StandardCharsets.UTF_8),
				password);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, String data, String password) {
		return Hex.encodeHexString(encrypt(type, enctyptionMode, type.getDefaultFillMode(),
				data.getBytes(StandardCharsets.UTF_8), password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, String data, String password) {
		return Base64.getEncoder().encodeToString(encrypt(type, enctyptionMode, type.getDefaultFillMode(),
				data.getBytes(StandardCharsets.UTF_8), password));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, byte[] data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(), data,
				password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, byte[] data,
			String password) {
		return Hex.encodeHexString(doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(),
				type.getDefaultOffset(), data, password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, byte[] data,
			String password) {
		return Base64.getEncoder().encodeToString(doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(),
				type.getDefaultOffset(), data, password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
				data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return Hex.encodeHexString(
				doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
						data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return Base64.getEncoder()
				.encodeToString(doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(),
						type.getDefaultOffset(), data.getBytes(StandardCharsets.UTF_8), password,
						StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password, StandardCharsets.UTF_8,
				Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password) {
		return Hex.encodeHexString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password,
				StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, byte[] data, String password) {
		return Base64.getEncoder().encodeToString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data,
				password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(StandardCharsets.UTF_8),
				password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password) {
		return Hex.encodeHexString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset,
				data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password) {
		return Base64.getEncoder().encodeToString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset,
				data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password, charset,
				Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password, Charset charset) {
		return Hex.encodeHexString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password,
				charset, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, byte[] data, String password, Charset charset) {
		return Base64.getEncoder().encodeToString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data,
				password, charset, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static byte[] encrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(charset), password, charset,
				Cipher.ENCRYPT_MODE);
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password, Charset charset) {
		return Hex.encodeHexString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(charset),
				password, charset, Cipher.ENCRYPT_MODE));
	}

	/**
	 * 使用特定的加密算法，加密模式和填充方式对数据进行加密.
	 * 
	 * @param type 加密算法类型
	 * @param enctyptionMode 加密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要加密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 加密异常
	 */
	public static String encryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password, Charset charset) {
		return Base64.getEncoder().encodeToString(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset,
				data.getBytes(charset), password, charset, Cipher.ENCRYPT_MODE));
	}

	// ############### decrypt

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, byte[] data, String password) {
		return decrypt(type, type.getDefaultEncryptionMode(), data, password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, String data, String password) {
		return decrypt(type, type.getDefaultEncryptionMode(), data.getBytes(StandardCharsets.UTF_8), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptHex(EncryptType type, String data, String password) {
		return decrypt(type, type.getDefaultEncryptionMode(), decodeHex(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptBase64(EncryptType type, String data, String password) {
		return decrypt(type, type.getDefaultEncryptionMode(), Base64.getDecoder().decode(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, byte[] data, String password) {
		return decrypt(type, enctyptionMode, type.getDefaultFillMode(), data, password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, String data, String password) {
		return decrypt(type, enctyptionMode, type.getDefaultFillMode(), data.getBytes(StandardCharsets.UTF_8),
				password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptHex(EncryptType type, EncryptionMode enctyptionMode, String data, String password)
			{
		return decrypt(type, enctyptionMode, type.getDefaultFillMode(), decodeHex(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptBase64(EncryptType type, EncryptionMode enctyptionMode, String data, String password) {
		return decrypt(type, enctyptionMode, type.getDefaultFillMode(), Base64.getDecoder().decode(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, byte[] data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(), data,
				password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
				data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
				decodeHex(data), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, String data,
			String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
				Base64.getDecoder().decode(data), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password, StandardCharsets.UTF_8,
				Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(StandardCharsets.UTF_8),
				password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, decodeHex(data), password,
				StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, Base64.getDecoder().decode(data), password,
				StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, byte[] data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password, charset,
				Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decrypt(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(charset), password, charset,
				Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptHex(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			@Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, decodeHex(data), password, charset,
				Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static byte[] decryptBase64(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, Base64.getDecoder().decode(data), password,
				charset, Cipher.DECRYPT_MODE);
	}

	// ############### decrypt toString

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, byte[] data, String password) {
		return decryptToString(type, type.getDefaultEncryptionMode(), data, password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, String data, String password) {
		return decryptToString(type, type.getDefaultEncryptionMode(), data.getBytes(StandardCharsets.UTF_8), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptHexToString(EncryptType type, String data, String password) {
		return decryptToString(type, type.getDefaultEncryptionMode(), decodeHex(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptBase64ToString(EncryptType type, String data, String password) {
		return decryptToString(type, type.getDefaultEncryptionMode(), Base64.getDecoder().decode(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, byte[] data,
			String password) {
		return decryptToString(type, enctyptionMode, type.getDefaultFillMode(), data, password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, String data,
			String password) {
		return decryptToString(type, enctyptionMode, type.getDefaultFillMode(),
				data.getBytes(StandardCharsets.UTF_8), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptHexToString(EncryptType type, EncryptionMode enctyptionMode, String data,
			String password) {
		return decryptToString(type, enctyptionMode, type.getDefaultFillMode(), decodeHex(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptBase64ToString(EncryptType type, EncryptionMode enctyptionMode, String data,
			String password) {
		return decryptToString(type, enctyptionMode, type.getDefaultFillMode(), Base64.getDecoder().decode(data), password);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			byte[] data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, type.getDefaultBlockSize(),
				type.getDefaultOffset(), data, password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
						data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptHexToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
						decodeHex(data), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptBase64ToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, type.getDefaultBlockSize(), type.getDefaultOffset(),
						Base64.getDecoder().decode(data), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, byte[] data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset, data, password,
				StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset,
				data.getBytes(StandardCharsets.UTF_8), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptHexToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset, decodeHex(data), password,
				StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptBase64ToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset,
				Base64.getDecoder().decode(data), password, StandardCharsets.UTF_8, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, byte[] data, String password, Charset charset) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset, data, password, charset,
				Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset, data.getBytes(charset),
				password, charset, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptHexToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password, Charset charset)
					{
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset, decodeHex(data), password,
				charset, Cipher.DECRYPT_MODE);
	}

	/**
	 * 使用特定的解密算法，加密模式和填充方式对数据进行解密.
	 * 
	 * @param type 解密算法类型
	 * @param enctyptionMode 解密模式
	 * @param fillMode 填充方式
	 * @param blockSize 数据块大小，也是密钥长度。参考{@link EncryptType}中的常量
	 * @param offset 偏移量。ECB加密模式不需要这个参数。参考{@link EncryptType}中的常量
	 * @param data 要解密的数据
	 * @param password 密码
	 * @param charset 编码。参考{@link StandardCharsets}
	 * @return 返回加密后的结果
	 * @throws IllegalArgumentException 解密异常
	 */
	public static String decryptBase64ToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode,
			int blockSize, @Nullable String offset, String data, String password, Charset charset) {
		return doEncOrDecToString(type, enctyptionMode, fillMode, blockSize, offset,
				Base64.getDecoder().decode(data), password, charset, Cipher.DECRYPT_MODE);
	}

	private static String doEncOrDecToString(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			String offset, byte[] data, String password, Charset charset, int mode) {
		String str = new String(doEncOrDec(type, enctyptionMode, fillMode, blockSize, offset, data, password, charset, mode),charset);
		return fillMode == FillMode.NoPadding || fillMode == FillMode.zeropadding ? str.trim() : str ;
	}
	
	private static byte[] doEncOrDec(EncryptType type, EncryptionMode enctyptionMode, FillMode fillMode, int blockSize,
			String offset, byte[] data, String password, Charset charset, int mode) {
		KeyGenerator kgen;
		try {
			kgen = KeyGenerator.getInstance(type.name());
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException("不支持的加密算法 - " + type, e);
		}
		FillMode fillModeTarget = fillMode ;
		if (fillMode == FillMode.zeropadding) {
			fillModeTarget = FillMode.NoPadding;
		}

		// 生成指定长度的密钥，这一步的目的是为了解决密钥定长，但是为了让使用者能够自定义密钥长度而产生的
		kgen.init(blockSize, new SecureRandom(password.getBytes(charset)));
		SecretKey key = kgen.generateKey();
		SecretKeySpec skeySpec = new SecretKeySpec(key.getEncoded(), type.name());

		Cipher cipher;
		try {
			// 设置加密算法，加密模式，填充方式
			cipher = Cipher.getInstance(type.name() + '/' + enctyptionMode.name() + '/' + fillModeTarget.name());
			// 0填充模式兼容处理
			if (fillModeTarget == FillMode.NoPadding) {
				data = zeropaddingCompatible(cipher, data);
			}
			if (enctyptionMode == EncryptionMode.ECB) {
				cipher.init(mode, skeySpec);
			} else {
				// 设置偏移量
				IvParameterSpec iv = new IvParameterSpec(offset.getBytes());
				cipher.init(mode, skeySpec, iv);
			}
			return cipher.doFinal(data);
		} catch (Exception e) {
			throw new IllegalArgumentException("解密异常：" + type.name() + "/" + enctyptionMode.name() + "/"
					+ fillMode.name() + " - " + blockSize + " - " + offset + " - " + charset + "\n【password】 = "
					+ password + "\n【data】 toString = " + new String(data), e);
		}
	}

	/**
	 * zeropadding加密模式兼容性处理
	 */
	private static byte[] zeropaddingCompatible(Cipher cipher, byte[] data) {
		int blockSize = cipher.getBlockSize();
		int length = data.length;
		if (length % blockSize != 0) {
			length = length + (blockSize - (length % blockSize));
		}
		byte[] plaintext = new byte[length];
		// 填充
		System.arraycopy(data, 0, plaintext, 0, data.length);
		return plaintext;
	}
	
	private static byte[] decodeHex(String data){
		try {
			return Hex.decodeHex(data);
		} catch (DecoderException e) {
			throw new IllegalArgumentException(e);
		}
	}

}
